#include <grass/gis.h>

#ifndef GRASS_G3D_H
#define GRASS_G3D_H

#define G3D_TILE_SAME_AS_FILE 2

#define G3D_NO_COMPRESSION 0
#define G3D_COMPRESSION 1

#define G3D_USE_LZW 1
#define G3D_NO_LZW 0

#define G3D_USE_RLE 1
#define G3D_NO_RLE 0

#define G3D_MAX_PRECISION -1

#define G3D_NO_CACHE 0
#define G3D_USE_CACHE_DEFAULT -1
#define G3D_USE_CACHE_X -2
#define G3D_USE_CACHE_Y -3
#define G3D_USE_CACHE_Z -4
#define G3D_USE_CACHE_XY -5
#define G3D_USE_CACHE_XZ -6
#define G3D_USE_CACHE_YZ -7
#define G3D_USE_CACHE_XYZ -8

#define G3D_DEFAULT_WINDOW NULL

#define G3D_DIRECTORY      "grid3"
#define G3D_CELL_ELEMENT   "cell"
#define G3D_CATS_ELEMENT   "cats"
#define G3D_RANGE_ELEMENT  "range"
#define G3D_HEADER_ELEMENT "cellhd"
#define G3D_HISTORY_ELEMENT "hist"
#define G3D_COLOR_ELEMENT  "color"
#define G3D_COLOR2_DIRECTORY  "colr2"
#define G3D_MASK_MAP       "G3D_MASK"
#define G3D_WINDOW_ELEMENT   "WIND3"
#define G3D_DEFAULT_WINDOW_ELEMENT   "DEFAULT_WIND3"
#define G3D_WINDOW_DATABASE "windows3d"
#define G3D_PERMANENT_MAPSET "PERMANENT"

/*---------------------------------------------------------------------------*/

typedef struct {

  double north, south;
  double east, west;
  double top, bottom;

  /* dimension of data in "cells"; rows == #x; cols == #y; depths == #z */
  int rows, cols, depths;

  double ns_res, ew_res, tb_res;

  int proj;  /* Projection (see gis.h) */
  int zone;  /* Projection zone (see gis.h) */

} G3D_Region;

/*---------------------------------------------------------------------------*/

struct G3D_Map;

typedef void resample_fn(struct G3D_Map *, int, int, int, void *, int);

/*---------------------------------------------------------------------------*/

typedef struct G3D_Map {

  char *fileName;
  char *tempName;
  char *mapset;

  /* operation performed on map */
     int operation; /* G3D_WRITE_DATA or G3D_READ_DATA */

  /* region */
     G3D_Region region;

  /* window for map */
     G3D_Region window;

  /* resmapling function used for map. default is nearest neighbor */
     resample_fn *resampleFun;

  /* units */
     char *unit;

  /* dimension of a single tile in "cells" */
     int tileX, tileY, tileZ;

  /* # of tiles in x, y, and z direction */
     int nx, ny, nz;

  /* data file specific information */

     /* file descriptor */
        int data_fd; /* file descriptor */

     /* type in which data is stored on file */
        int type; /* DCELL_TYPE or FCELL_TYPE */

     /* data concering the compression */
        int precision; /* G3D_MAX_PRECISION or, 0 .. 23 for float, 
		                                0 .. 52 for double */
        int compression; /* G3D_NO_COMPRESSION or G3D_USE_COMPRESSION */
        int useLzw; /* G3D_USE_LZW or G3D_NO_LZW */
        int useRle; /* G3D_USE_RLE or G3D_NO_RLE */
        int useXdr; /* G3D_USE_XDR or G3D_NO_XDR */
     
     /* pointer to first tile in file */
        int offset;

     /* pointer to the first index entry in file */
        long indexOffset;
  
     /* sizeof (long) of the system on which the file is/was written */
        int indexLongNbytes;

     /* max # bytes used in the representation of indices; this is equal to */
     /* # bytes used in the representation of "indexOffset" */
        int indexNbytesUsed;

     /* pointer to the last entry in the file */
        int fileEndPtr;
      
     /* indicates if index is stored in file; used for G3D_READ_DATA only */
        int hasIndex; /* G3D_HAS_INDEX or G3D_NO_INDEX */

  /* information concerning internal storage of data */

     /* index specific information */
        /* index[i] == the offset of tile "i" in the data file */
           long *index;

        /* tileLength[i] == # bytes used to store tile "i" */
           int *tileLength;

     /* tile specific information */

        /* type in which data is stored in memory */
           int typeIntern; /* DCELL_TYPE or FCELL_TYPE */

     /* in non-cache mode the "data" array is used to store one tile */
        char *data;
     
     /* index of tile currently stored in "data"; -1 if none */
        int currentIndex;

     /* cache related variables */

        int useCache;   /* 1 if cache is used */
        void *cache;    /* pointer to cache structure */
        int cacheFD;    /* file discriptor of cache file -- write mode only */
        char *cacheFileName; /* filename of cache file -- write mode only */
        long cachePosLast; /* position of last entry in cache file -- write */
                           /* mode only*/

  /* range info */
     struct FPRange range;

  /* some constants stored for efficiency */
        
     /* number of bytes required to store a single value of "type" */
        int numLengthExtern;
  
     /* number of bytes required to store a single value of "typeIntern" */
        int numLengthIntern;

     /* see header.c for details */
        int clipX, clipY, clipZ;
        int tileXY, tileSize;     
        int nxy, nTiles;

  /* mask related information */

     int useMask; /* 1 if mask is used; 0 otherwise */

} G3D_Map;

/*---------------------------------------------------------------------------*/

typedef struct {
  
  char *elts;       /* ptr to array of elts */
  int nofElts;      /* size of "elts" */
  int eltSize;      /* size of elt in "elts" */

  int *names;       /* name[i] is the name of elts[i] */

  char *locks;      /* lock[i] == 1 iff elts[i] is locked
                       lock[i] == 0 iff elts[i] is unlocked but active
                       lock[i] == 2 iff elts[i] doesn't contain valid data */
  int autoLock;     /* 1 if auto locking is turned on */
  int nofUnlocked;  /* nof tiles which are unlocked */
  int minUnlocked;  /* min nof elts which have to remain unlocked. min = 1 */

  int *next, *prev; /* prev/next pointers for fifo */
  int first, last;  /* index (into next) of first and last elt in fifo */
                    /* first == -1 iff fifo is empty */

  int (* eltRemoveFun) (); /* callback activated if the contents of an 
			       elt needs to be removed */
  void *eltRemoveFunData;   /* pointer to user data passed along with 
			       eltRemoveFun */
  int (* eltLoadFun) ();   /* callback activated to load contents of an elt */
  void *eltLoadFunData;     /* pointer to user data passed along with 
			       eltLoadFun */

  void *hash;       /* ptr to hashTable used to relate external names to
                       internal indices (elts) */

} G3D_cache;

/*---------------------------------------------------------------------------*/

typedef struct {

  int nofNames;
  int *index;
  char *active;
  int lastName;
  int lastIndex;
  int lastIndexActive;

} G3d_cache_hash;

/*---------------------------------------------------------------------------*/

typedef int write_fn(int, const void *, void *);
typedef int read_fn(int, void *, void *);

/*---------------------------------------------------------------------------*/

/* grass/src/libes/g3d/cache.c */
void G3d_cache_reset(G3D_cache *);
void G3d_cache_dispose(G3D_cache *);
void *G3d_cache_new(int, int, int, write_fn *, void *, read_fn *, void *);
void G3d_cache_set_removeFun(G3D_cache *, write_fn *, void *);
void G3d_cache_set_loadFun(G3D_cache *, read_fn *, void *);
void *G3d_cache_new_read(int, int, int, read_fn *, void *);
int G3d_cache_lock(G3D_cache *, int);
void G3d_cache_lock_intern(G3D_cache *, int);
int G3d_cache_unlock(G3D_cache *, int);
int G3d_cache_unlock_all(G3D_cache *);
int G3d_cache_lock_all(G3D_cache *);
void G3d_cache_autolock_on(G3D_cache *);
void G3d_cache_autolock_off(G3D_cache *);
void G3d_cache_set_minUnlock(G3D_cache *, int);
int G3d_cache_remove_elt(G3D_cache *, int);
int G3d_cache_flush(G3D_cache *, int);
int G3d_cache_remove_all(G3D_cache *);
int G3d_cache_flush_all(G3D_cache *);
void *G3d_cache_elt_ptr(G3D_cache *, int);
int G3d_cache_load(G3D_cache *, int);
int G3d_cache_get_elt(G3D_cache *, int, void *);
int G3d_cache_put_elt(G3D_cache *, int, const void *);
/* grass/src/libes/g3d/cachehash.c */
void G3d_cache_hash_reset(G3d_cache_hash *);
void G3d_cache_hash_dispose(G3d_cache_hash *);
void *G3d_cache_hash_new(int);
void G3d_cache_hash_remove_name(G3d_cache_hash *, int);
void G3d_cache_hash_load_name(G3d_cache_hash *, int, int);
int G3d_cache_hash_name2index(G3d_cache_hash *, int);
/* grass/src/libes/g3d/changeprecision.c */
void G3d_changePrecision(void *, int, const char *);
/* grass/src/libes/g3d/changetype.c */
void G3d_changeType(void *, const char *);
/* grass/src/libes/g3d/filecompare.c */
void G3d_compareFiles(const char *, const char *, const char *, const char *);
/* grass/src/libes/g3d/filename.c */
void G3d_filename(char *, const char *, const char *, const char *);
/* grass/src/libes/g3d/find_grid3.c */
char *G_find_grid3(const char *, const char *);
/* grass/src/libes/g3d/fpcompress.c */
void G_fpcompress_printBinary(char *, int);
void G_fpcompress_dissectXdrDouble(unsigned char *);
int G_fpcompress_writeXdrNums(int, char *, int, int, char *, int, int, int);
int G_fpcompress_writeXdrFloats(int, char *, int, int, char *, int, int);
int G_fpcompress_writeXdrDouble(int, char *, int, int, char *, int, int);
int G_fpcompress_readXdrNums(int, char *, int, int, int, char *, int);
int G_fpcompress_readXdrFloats(int, char *, int, int, int, char *);
int G_fpcompress_readXdrDoubles(int, char *, int, int, int, char *);
/* grass/src/libes/g3d/g3dalloc.c */
void *G3d_malloc(int);
void *G3d_realloc(void *, int);
void G3d_free(void *);
/* grass/src/libes/g3d/g3dcache.c */
int G3d_initCache(G3D_Map *, int);
int G3d_disposeCache(G3D_Map *);
int G3d_flushAllTiles(G3D_Map *);
/* grass/src/libes/g3d/g3dcats.c */
int G3d_writeCats(const char *, struct Categories *);
int G3d_readCats(const char *, const char *, struct Categories *);
/* grass/src/libes/g3d/g3dclose.c */
int G3d_closeCell(G3D_Map *);
/* grass/src/libes/g3d/g3dcolor.c */
int G3d_removeColor(const char *);
int G3d_readColors(const char *, const char *, struct Colors *);
int G3d_writeColors(const char *, const char *, struct Colors *);
/* grass/src/libes/g3d/g3ddefaults.c */
void G3d_setCompressionMode(int, int, int, int);
void G3d_getCompressionMode(int *, int *, int *, int *);
void G3d_setCacheSize(int);
int G3d_getCacheSize(void);
void G3d_setCacheLimit(int);
int G3d_getCacheLimit(void);
void G3d_setFileType(int);
int G3d_getFileType(void);
void G3d_setTileDimension(int, int, int);
void G3d_getTileDimension(int *, int *, int *);
void G3d_setErrorFun(void (*)(const char *));
void G3d_setUnit(const char *);
void G3d_initDefaults(void);
/* grass/src/libes/g3d/g3ddoubleio.c */
int G3d_writeDoubles(int, int, const double *, int);
int G3d_readDoubles(int, int, double *, int);
/* grass/src/libes/g3d/g3derror.c */
void G3d_skipError(const char *);
void G3d_printError(const char *);
void G3d_fatalError(const char *, ...) __attribute__((format(printf,1,2))) __attribute__((noreturn));
void G3d_fatalError_noargs(const char *) __attribute__((noreturn));
void G3d_error(const char *, ...) __attribute__((format(printf,1,2)));
/* grass/src/libes/g3d/g3dfpxdr.c */
int G3d_isXdrNullNum(const void *, int);
int G3d_isXdrNullFloat(const float *);
int G3d_isXdrNullDouble(const double *);
void G3d_setXdrNullNum(void *, int);
void G3d_setXdrNullDouble(double *);
void G3d_setXdrNullFloat(float *);
int G3d_initFpXdr(G3D_Map *, int);
int G3d_initCopyToXdr(G3D_Map *, int);
int G3d_copyToXdr(const void *, int);
int G3d_initCopyFromXdr(G3D_Map *, int);
int G3d_copyFromXdr(int, void *);
/* grass/src/libes/g3d/g3dhistory.c */
int G3d_writeHistory(const char *, struct History *);
int G3d_readHistory(const char *, const char *, struct History *);
/* grass/src/libes/g3d/g3dintio.c */
int G3d_writeInts(int, int, const int *, int);
int G3d_readInts(int, int, int *, int);
/* grass/src/libes/g3d/g3dkeys.c */
int G3d_keyGetInt (struct Key_Value *, const char *, int *);
int G3d_keyGetDouble (struct Key_Value *, const char *, double *);
int G3d_keyGetString (struct Key_Value *, const char *, char **);
int G3d_keyGetValue (struct Key_Value *, const char *, char *, char *, int, int, int *);
int G3d_keySetInt (struct Key_Value *, const char *, const int *);
int G3d_keySetDouble (struct Key_Value *, const char *, const double *);
int G3d_keySetString (struct Key_Value *, const char *, char * const *);
int G3d_keySetValue (struct Key_Value *, const char *, const char *, const char *, int, int, const int *);
/* grass/src/libes/g3d/g3dlong.c */
int G3d_longEncode(long *, unsigned char *, int);
void G3d_longDecode(unsigned char *, long *, int, int);
/* grass/src/libes/g3d/g3dmapset.c */
void G3d_makeMapsetMapDirectory(const char *);
/* grass/src/libes/g3d/g3dmask.c */
int G3d_maskClose(void);
int G3d_maskFileExists(void);
int G3d_maskOpenOld(void);
int G3d_maskReopen(int);
int G3d_isMasked(G3D_Map *, int, int, int);
void G3d_maskNum(G3D_Map *, int, int, int, void *, int);
void G3d_maskFloat(G3D_Map *, int, int, int, float *);
void G3d_maskDouble(G3D_Map *, int, int, int, double *);
void G3d_maskTile(G3D_Map *, int, void *, int);
void G3d_maskOn(G3D_Map *);
void G3d_maskOff(G3D_Map *);
int G3d_maskIsOn(G3D_Map *);
int G3d_maskIsOff(G3D_Map *);
const char *G3d_maskFile(void);
int G3d_maskMapExists(void);
/* grass/src/libes/g3d/g3dmisc.c */
int G3d_g3dType2cellType(int);
void G3d_copyFloat2Double(const float *, int, double *, int, int);
void G3d_copyDouble2Float(const double *, int, float *, int, int);
void G3d_copyValues(const void *, int, int, void *, int, int, int);
int G3d_length(int);
int G3d_externLength(int);
/* grass/src/libes/g3d/g3dnull.c */
int G3d_isNullValueNum(const void *, int);
void G3d_setNullValue(void *, int, int);
/* grass/src/libes/g3d/g3dopen2.c */
/* grass/src/libes/g3d/g3dopen.c */
void *G3d_openCellOldNoHeader(const char *, const char *);
void * G3d_openCellOld (const char *, const char * , G3D_Region *, int, int);
void * G3d_openCellNew (const char *, int, int, G3D_Region * );
/* grass/src/libes/g3d/g3dparam.c */
void G3d_setStandard3dInputParams(void);
int G3d_getStandard3dParams(int *, int *, int *, int *, int *, int *, int *, int *, int *, int *, int *, int *);
void G3d_setWindowParams(void);
char *G3d_getWindowParams(void);
/* grass/src/libes/g3d/g3drange.c */
void G3d_range_updateFromTile(G3D_Map *, const void *, int, int, int, int, int, int, int, int);
int G3d_readRange(const char *, const char *, struct FPRange *);
int G3d_range_load(G3D_Map *);
void G3d_range_min_max(G3D_Map *, double *, double *);
int G3d_range_write(G3D_Map *);
int G3d_range_init(G3D_Map *);
/* grass/src/libes/g3d/g3dregion.c */
void G3d_getRegionValue(G3D_Map *, double, double, double, void *, int);
void G3d_adjustRegion (G3D_Region *);
void G3d_regionCopy (G3D_Region *,G3D_Region *);
void G3d_incorporate2dRegion (struct Cell_head *, G3D_Region *);
void G3d_regionFromToCellHead (struct Cell_head *, G3D_Region *);
void G3d_adjustRegionRes (G3D_Region *);
void G3d_extract2dRegion (G3D_Region *, struct Cell_head *);
void G3d_regionToCellHead (G3D_Region *, struct Cell_head *);
int G3d_readRegionMap (const char *, const char *,G3D_Region *);

/* grass/src/libes/g3d/g3dresample.c */
void G3d_nearestNeighbor(G3D_Map *, int, int, int, void *, int);
void G3d_setResamplingFun(G3D_Map *, void (*)());
void G3d_getResamplingFun(G3D_Map *, void (**)());
void G3d_getNearestNeighborFunPtr(void (**)());
/* grass/src/libes/g3d/g3dvolume.c */
void G3d_getVolumeA(void *, double [2][2][2][3], int, int, int, void *, int);
void G3d_getVolume(void *, double, double, double, double, double, double, double, double, double, double, double, double, int, int, int, void *, int);
void G3d_getAlignedVolume(void *, double, double, double, double, double, double, int, int, int, void *, int);
void G3d_makeAlignedVolumeFile(void *, const char *, double, double, double, double, double, double, int, int, int);
/* grass/src/libes/g3d/g3dwindow.c */
void G3d_getValue(G3D_Map *, int, int, int, void *, int);
float G3d_getFloat(G3D_Map *, int, int, int);
double G3d_getDouble(G3D_Map *, int, int, int);
G3D_Region * G3d_windowPtr (void);
void G3d_setWindow (G3D_Region *);
void G3d_setWindowMap (G3D_Map *, G3D_Region *);
void G3d_getWindow (G3D_Region *);

/* grass/src/libes/g3d/g3dwindowio.c */
void G3d_useWindowParams(void);
int G3d_readWindow (G3D_Region *, const char *);
/* int G3d_writeWindow (G3D_Region *, char *); */
/* grass/src/libes/g3d/getblock.c */
void G3d_getBlockNocache(G3D_Map *, int, int, int, int, int, int, void *, int);
void G3d_getBlock(G3D_Map *, int, int, int, int, int, int, void *, int);
/* grass/src/libes/g3d/header.c */
int G3d_readHeader(G3D_Map *, int *, int *, double *, double *, double *, double *, double *, double *, int *, int *, int *, double *, double *, double *, int *, int *, int *, int *, int *, int *, int *, int *, int *, int *, int *, char **);
int G3d_writeHeader(G3D_Map *, int, int, double, double, double, double, double, double, int, int, int, double, double, double, int, int, int, int, int, int, int, int, int, int, int, char *);
int G3d_cacheSizeEncode(int, int);
int G3d__computeCacheSize(G3D_Map *, int);
int G3d_fillHeader(G3D_Map *, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, double, double, double, double, double, double, int, int, int, double, double, double, char *);
/* grass/src/libes/g3d/headerinfo.c */
void G3d_getCoordsMap(G3D_Map *, int *, int *, int *);
void G3d_getCoordsMapWindow(G3D_Map *, int *, int *, int *);
void G3d_getNofTilesMap(G3D_Map *, int *, int *, int *);
void G3d_getRegionMap(G3D_Map *, double *, double *, double *, double *, double *, double *);
void G3d_getWindowMap(G3D_Map *, double *, double *, double *, double *, double *, double *);
void G3d_getTileDimensionsMap(G3D_Map *, int *, int *, int *);
int G3d_tileTypeMap(G3D_Map *);
int G3d_fileTypeMap(G3D_Map *);
int G3d_tilePrecisionMap(G3D_Map *);
int G3d_tileUseCacheMap(G3D_Map *);
void G3d_printHeader(G3D_Map *);
void G3d_getRegionStructMap (G3D_Map *, G3D_Region *);
/* grass/src/libes/g3d/index.c */
int G3d_flushIndex(G3D_Map *);
int G3d_initIndex(G3D_Map *, int);
/* grass/src/libes/g3d/retile.c */
void G3d_retile(void *, const char *, int, int, int);
/* grass/src/libes/g3d/rle.c */
int G_rle_count_only(char *, int, int);
void G_rle_encode(char *, char *, int, int);
void G_rle_decode(char *, char *, int, int, int *, int *);
/* grass/src/libes/g3d/tilealloc.c */
void *G3d_allocTilesType(G3D_Map *, int, int);
void *G3d_allocTiles(G3D_Map *, int);
void G3d_freeTiles(void *);
/* grass/src/libes/g3d/tileio.c */
void *G3d_getTilePtr(G3D_Map *, int);
int G3d_tileLoad(G3D_Map *, int);
int G3d__removeTile(G3D_Map *, int);
float G3d_getFloatRegion(G3D_Map *, int, int, int);
double G3d_getDoubleRegion(G3D_Map *, int, int, int);
void G3d_getValueRegion(G3D_Map *, int, int, int, void *, int);
/* grass/src/libes/g3d/tilemath.c */
void G3d_tileIndex2tile(G3D_Map *, int, int *, int *, int *);
int G3d_tile2tileIndex(G3D_Map *, int, int, int);
void G3d_tileCoordOrigin(G3D_Map *, int, int, int, int *, int *, int *);
void G3d_tileIndexOrigin(G3D_Map *, int, int *, int *, int *);
void G3d_coord2tileCoord(G3D_Map *, int, int, int, int *, int *, int *, int *, int *, int *);
void G3d_coord2tileIndex(G3D_Map *, int, int, int, int *, int *);
int G3d_coordInRange(G3D_Map *, int, int, int);
int G3d_tileIndexInRange(G3D_Map *, int);
int G3d_tileInRange(G3D_Map *, int, int, int);
int G3d_computeClippedTileDimensions(G3D_Map *, int, int *, int *, int *, int *, int *, int *);
int G3d_isValidLocation(G3D_Map *, double, double, double);
void G3d_location2coord(G3D_Map *, double, double, double, int *, int *, int *);
/* grass/src/libes/g3d/tilenull.c */
void G3d_setNullTileType(G3D_Map *, void *, int);
void G3d_setNullTile(G3D_Map *, void *);
/* grass/src/libes/g3d/tileread.c */
int G3d_readTile(G3D_Map *, int, void *, int);
int G3d_readTileFloat(G3D_Map *, int, void *);
int G3d_readTileDouble(G3D_Map *, int, void *);
int G3d_lockTile(G3D_Map *, int);
int G3d_unlockTile(G3D_Map *, int);
int G3d_unlockAll(G3D_Map *);
void G3d_autolockOn(G3D_Map *);
void G3d_autolockOff(G3D_Map *);
void G3d_minUnlocked(G3D_Map *, int);
int G3d_beginCycle(G3D_Map *);
int G3d_endCycle(G3D_Map *);
/* grass/src/libes/g3d/tilewrite.c */
int G3d_writeTile(G3D_Map *, int, const void *, int);
int G3d_writeTileFloat(G3D_Map *, int, const void *);
int G3d_writeTileDouble(G3D_Map *, int, const void *);
int G3d_flushTile(G3D_Map *, int);
int G3d_flushTileCube(G3D_Map *, int, int, int, int, int, int);
int G3d_flushTilesInCube(G3D_Map *, int, int, int, int, int, int);
int G3d_putFloat(G3D_Map *, int, int, int, float);
int G3d_putDouble(G3D_Map *, int, int, int, double);
int G3d_putValue(G3D_Map *, int, int, int, const void *, int);
/* grass/src/libes/g3d/writeascii.c */
void G3d_writeAscii(void *, const char *);

#endif /* #ifndef GRASS_G3D_H */
